package controllers
import (
	"io/ioutil"
	"strings"
	"net/http"
	"os"
	"ServerGo/common"
	"os/exec"
	"github.com/bitly/go-simplejson"
	"strconv"
	"time"
	"sort"
	"path/filepath"
)

// @router /back2PrevResponse.php [Post]
// @binding controllers.EmptyParams
func Back2PrevResponse(params EmptyParams, res http.ResponseWriter, req *http.Request) string {
	isSameUser := isSameUser(req.Form.Get("username"), req.Form.Get("modulename"))
	_, err := os.Stat(RECORD_PATH)
	if (err == nil || os.IsExist(err)) && !isSameUser {
		recordInfo, _ := ioutil.ReadFile(RECORD_PATH)
		recordInfos := strings.Split(string(recordInfo), "|")
		os.Remove(RECORD_PATH)

		var errInfo string = "you are not the uploader of "+recordInfos[1]+", please concat " +recordInfos[0]
		common.Logger(common.LOG_WARNING, errInfo)
		return common.Object2JsonStr(ResponseMsg{1, errInfo, nil})

	}else {
		md5Str := `db46d555cf435a8ec701e7ed7cec422d`
		if (req.Form.Get("token") != md5Str) {
			os.Remove(RECORD_PATH)
			var errInfo string = "new autoload parse error"
			common.Logger(common.LOG_WARNING, errInfo)
			return common.Object2JsonStr(ResponseMsg{2, "token error", nil})
		}else {
			username := req.Form.Get("username")
			module := req.Form.Get("modulename")
			typeStr := req.Form.Get("type")

			if typeStr == "1" {
				cmd := exec.Command("/bin/sh", "-c", "cd "+BUILD_PATH+" && git pull")
				_, err := cmd.CombinedOutput()
				if err != nil {
					var errInfo string = "git pull faild"
					common.Logger(common.LOG_WARNING, errInfo)
					return common.Object2JsonStr(ResponseMsg{7, errInfo, nil})
				}

				buildInfo, _ := ioutil.ReadFile(BUILD_PATH+"/index.json")
				j, _ := simplejson.NewJson(buildInfo)
				access, _ := j.Get("access").StringArray()
				userExists := false

				for _, v := range access {
					if v == req.Form.Get("username") {
						userExists = true
						break
					}
				}

				if userExists {
					var errInfo string = username+" isn't in access"
					common.Logger(common.LOG_WARNING, errInfo)
					return common.Object2JsonStr(ResponseMsg{8, errInfo, nil})
				}

				defer os.Remove(RECORD_PATH)

				if !isSameUser {
					content := username + "|" + module +"|"+strconv.Itoa(int(time.Now().Unix()))
					err := ioutil.WriteFile(RECORD_PATH, []byte(content), 0777)

					if err != nil {
						var errInfo string = "write file faild"
						common.Logger(common.LOG_WARNING, errInfo)
						return common.Object2JsonStr(ResponseMsg{5, errInfo, nil})
					}
				}

				common.Logger(common.LOG_INFO, "success")
				return common.Object2JsonStr(ResponseMsg{0, "success", nil})

			}else if typeStr == "2" {
				defer os.Remove(RECORD_PATH)
				_, err := os.Stat(RECORD_PATH)
				if err == nil || os.IsExist(err) {
					err = os.Remove(RECORD_PATH)
					if err != nil {
						var errInfo string = "unlink record file faild"
						common.Logger(common.LOG_WARNING, errInfo)
						return common.Object2JsonStr(ResponseMsg{9, errInfo, nil})
					}

					common.Logger(common.LOG_INFO, "success")
					return common.Object2JsonStr(ResponseMsg{0, "success", nil})
				}
			}else {
				defer os.Remove(RECORD_PATH)
				dirpath := getLastDir(module)
				if dirpath == "" {
					var errInfo string = "back dir is empty"
					common.Logger(common.LOG_WARNING, errInfo)
					return common.Object2JsonStr(ResponseMsg{10, errInfo, nil})
				}else {
					basepath := TMP_PATH_PREFIX+"/"+module+"/"+dirpath
					back2Prev(basepath+"/map.txt")
					err := dumpload(basepath, req.Form.Get("composerTo"))

					if err != nil {
						var errInfo string = "exec faild"
						common.Logger(common.LOG_WARNING, errInfo)
						return common.Object2JsonStr(ResponseMsg{4, errInfo, nil})
					}

					os.RemoveAll(basepath)
					common.Logger(common.LOG_INFO, "success")
					return common.Object2JsonStr(ResponseMsg{0, "success", nil})
				}
			}
		}
	}

	os.Remove(RECORD_PATH)
	return common.Object2JsonStr(ResponseMsg{0, "success", nil})
}

func isSameUser(username string, module string) bool {
	recordInfo, err := ioutil.ReadFile(RECORD_PATH)
	if err != nil {
		return false
	}

	recordInfos := strings.Split(string(recordInfo), "|")
	return recordInfos[0] == username && recordInfos[1] == module
}

func getLastDir(module string) string {
	dirpath := TMP_PATH_PREFIX+"/"+module
	_, err := os.Stat(dirpath)
	if !(err == nil || os.IsExist(err)) {
		return ""
	}

	dirs, err := ioutil.ReadDir(dirpath)
	if err != nil {
		return ""
	}

	tmp := make([]string, 0)
	for _, fi := range dirs {
		filename := fi.Name()
		if filename == "." || filename == ".." || strings.HasPrefix(filename, ".") {
			continue
		}else {
			tmp = append(tmp, filename)
		}
	}

	if len(tmp) != 0 {
		sort.Strings(tmp)
		return tmp[len(tmp)-1]
	}

	return ""
}

func back2Prev(path string) {
	bytes, _ := ioutil.ReadFile(path)
	items := strings.Split(string(bytes), "\n")
	for _, v := range items {
		item := strings.Split(v, "->")
		if (len(item) < 2) {
			continue
		}

		item[0] = strings.TrimSpace(item[0])
		item[1] = strings.TrimSpace(item[1])
		dirpath := filepath.Dir(item[0])
		_, err := os.Stat(dirpath)

		if !(err == nil || os.IsExist(err)) {
			os.MkdirAll(dirpath, 0777)
		}

		_, err = os.Stat(item[0])
		if err == nil || os.IsExist(err) {
			os.Remove(item[0])
		}

		bytes, _ := ioutil.ReadFile(item[1])
		ioutil.WriteFile(item[0], bytes, 0777)
		os.Remove(item[1])
	}
}

func dumpload(path string, module string) error {
	autoload := path+"/composer.json"
	installed := path+"/installed.json"
	mapTxt := path+"/map.txt"

	bytes, _ := ioutil.ReadFile(mapTxt)
	items := strings.Split(string(bytes), "\n")
	item := strings.Split(items[0], "->")
	item[0] = strings.TrimSpace(item[0])

	index := strings.Index(item[0], module)+len(module)
	dirpath := item[0][:index]

	_, err := os.Stat(autoload)
	if !(err == nil || os.IsExist(err)) {
		return err
	}

	bytes, err = ioutil.ReadFile(autoload)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(dirpath+"/composer.json", bytes, 0777)
	if err != nil {
		return err
	}

	_, err = os.Stat(installed)
	if !(err == nil || os.IsExist(err)) {
		return err
	}

	bytes, err = ioutil.ReadFile(installed)
	if err != nil {
		return err
	}

	err = ioutil.WriteFile(dirpath+"/vendor/composer/installed.json", bytes, 0777)
	if err != nil {
		return err
	}

	cmd := exec.Command("/bin/sh", "-c", "cd "+dirpath+" && COMPOSER_HOME=\"/tmp\" php composer.phar dump-autoload -o")
	_, err = cmd.CombinedOutput()
	if err != nil {
		return err
	}

	return nil
}